﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Windows.Forms;
using NETCommon;
using NETCommon.Files;

namespace NETCommon.Communication
{
    public class NWin32API
    {
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        //For use with WM_COPYDATA and COPYDATASTRUCT
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);

        [DllImport("User32.dll", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("User32.dll")]
        private static extern Int32 SetForegroundWindow(int hWnd);

        public const int WM_COPYDATA = 0x004A;
        public const int WM_CLOSE = 0x0010;
        public const int WM_USER = 0x0400;
        public const int WM_SETFOCUS = 0x0005;
        public const int WM_SHOWWINDOW = 0x0018;
        public const int WM_SYSCOMMAND = 0x0112;

        public const int SC_RESTORE = 0xF120;
        public const int SC_MAXIMIZE = 0xF100;
        public const int SC_MINIMIZE = 0xF020;

        public const int UM_SINGLE_POINT_MSG = WM_USER + 2002;
        public const int UM_UNIVIEW_CONNECT_REQUEST = WM_USER + 2001;
        public const int UM_MULTIPLE_POINT_MSG = WM_USER + 2000; 

        public struct COPYDATASTRUCT
        {
            public IntPtr dwData { get; set; }
            public int cbData { get; set; }
            public IntPtr lpData { get; set; }
        }
        public static void CloseWindow(string windowTitle)
        {
            IntPtr wndPtr = NWin32API.FindWindow(null, windowTitle);
            if (wndPtr != IntPtr.Zero)
            {
                NWin32API.SendMessage(wndPtr, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
            }
        }
        public static void RestoreWindow(string windowTitle)
        {
            IntPtr wndPtr = NWin32API.FindWindow(null, windowTitle);
            if (wndPtr != IntPtr.Zero)
            {
                NWin32API.SendMessage(wndPtr, NWin32API.WM_SYSCOMMAND, (IntPtr)NWin32API.SC_RESTORE, IntPtr.Zero);
            }
        }
        public static void ActiveWindow(string windowTitle)
        {
            IntPtr wndPtr = NWin32API.FindWindow(null, windowTitle);
            if (wndPtr != IntPtr.Zero)
            {
                SetForegroundWindow((int)wndPtr);
            }
        }
        public static IntPtr FindWindow(string windowTitle)
        {
            IntPtr wndPtr = NWin32API.FindWindow(null, windowTitle);
            return wndPtr;
        }
        public static IntPtr FindWindows(string[] windowTitle)
        {
            IntPtr WindowPtr = IntPtr.Zero;

            foreach (string title in windowTitle)
            {
                WindowPtr = NWin32API.FindWindow(null, title);
                if (WindowPtr != IntPtr.Zero)
                    return WindowPtr;
            }

            return WindowPtr;
        }

        public static void CloseWindow(IntPtr wndPtr)
        {
            if (wndPtr != IntPtr.Zero)
            {
                NWin32API.SendMessage(wndPtr, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
            }
        }
        public static void RestoreWindow(IntPtr wndPtr)
        {
            if (wndPtr != IntPtr.Zero)
            {
                NWin32API.SendMessage(wndPtr, NWin32API.WM_SYSCOMMAND, (IntPtr)NWin32API.SC_RESTORE, IntPtr.Zero);
            }
        }
        public static void ActiveWindow(IntPtr wndPtr)
        {
            if (wndPtr != IntPtr.Zero)
            {
                SetForegroundWindow((int)wndPtr);
            }
        }

        public static void SendCopyMessage(string windowTitle, int UM_MSGID, object DataObj)
        {
            IntPtr wndPtr = NWin32API.FindWindow(null, windowTitle);
            if (wndPtr != IntPtr.Zero)
            {
                COPYDATASTRUCT strData = new COPYDATASTRUCT();
                strData.cbData = System.Runtime.InteropServices.Marshal.SizeOf(DataObj);
                strData.dwData = (IntPtr)UM_MSGID;
                IntPtr ptr = System.Runtime.InteropServices.Marshal.AllocHGlobal(strData.cbData);
                System.Runtime.InteropServices.Marshal.StructureToPtr(DataObj, ptr, true);
                strData.lpData = ptr;

                NWin32API.SendMessage((int)wndPtr, (int)NWin32API.WM_COPYDATA, (int)IntPtr.Zero, ref strData);
            }
        }
        public static void SendMessage(string windowTitle, uint UM_MSGID, IntPtr wParam, IntPtr lParam)
        {
            IntPtr wndPtr = NWin32API.FindWindow(null, windowTitle);
            if (wndPtr != IntPtr.Zero)
            {
                SendMessage(wndPtr, UM_MSGID,  wParam, lParam);
            }
        }    
        public static object ReceiveCopyMessage(ref System.Windows.Forms.Message msg, int UM_MSGID, Type myType)
        {
            object ret = null;
            if (msg.Msg == NWin32API.WM_COPYDATA)
            {
                COPYDATASTRUCT m = new COPYDATASTRUCT();
                m = (NWin32API.COPYDATASTRUCT)msg.GetLParam(m.GetType());

                if (m.dwData.ToInt32() == UM_MSGID)
                {
                    ret = System.Runtime.InteropServices.Marshal.PtrToStructure(m.lpData, myType);
                }
            }
            
            return ret;
        }

        private delegate void ProcessStartNSendDelegate(bool ForceToSend);
        
        private static void ProcessStartNSend(bool ForceToSend)
        { 
           bool isRunning=false;
           Start(myData.exeFilename, new string[] { myData.windowTitle }, true, myData.argv,out isRunning);
           if (isRunning || ForceToSend)
           {
               SendCopyMessage(myData.windowTitle, myData.UM_MSGID, myData.DataObj);
           }
        }
        
        private static MesasgeData myData;

        //Run file, findwindow if exist
        public static IntPtr Start(string exeFilename,string[] windowTitle,Boolean isBlocking, string argv)
        {
            try
            {
                IntPtr WindowPtr = IntPtr.Zero;
                if (exeFilename.IndexOf('\\') < 0)
                    exeFilename = AppDomain.CurrentDomain.BaseDirectory + exeFilename;

                if (windowTitle == null)
                {
                    if (!File.Exists(exeFilename))
                        return IntPtr.Zero;
                    else
                    {
                        System.Diagnostics.Process process = null;
                        if (string.IsNullOrEmpty(argv))
                            process = System.Diagnostics.Process.Start(exeFilename);
                        else
                            process = System.Diagnostics.Process.Start(exeFilename, argv);

                        return process.Handle;
                    }
                }
                else
                {
                    WindowPtr = FindWindows(windowTitle);

                    if (WindowPtr != IntPtr.Zero)
                    {
                        NWin32API.ActiveWindow(WindowPtr);
                    }
                    else
                    {
                        if (!File.Exists(exeFilename))
                            return IntPtr.Zero;

                        System.Diagnostics.Process process = null;
                        if (string.IsNullOrEmpty(argv))
                            process = System.Diagnostics.Process.Start(exeFilename);
                        else
                            process = System.Diagnostics.Process.Start(exeFilename, argv);

                        System.Threading.Thread.Sleep(250);

                        if (process != null && isBlocking)
                        {
                            //*
                            int cnt = 0;
                            do
                            {
                                System.Threading.Thread.Sleep(250);
                                WindowPtr = FindWindows(windowTitle);
                                Console.WriteLine("Windows:{0} Count{1}", WindowPtr.ToInt32(), cnt);
                                cnt++;
                            } while (WindowPtr == IntPtr.Zero && cnt < 30);
                            //*/ 

                        }

                    }

                    if (WindowPtr != IntPtr.Zero)
                    {
                        NWin32API.SendMessage(WindowPtr, NWin32API.WM_SYSCOMMAND, (IntPtr)NWin32API.SC_RESTORE, IntPtr.Zero);
                    }
                    else
                    {
                        if (isBlocking)
                        {
                            string str = "";
                            foreach (string temp in windowTitle)
                            {
                                str += temp + ",";
                            }
                            str = str.Remove(str.Length - 1);
                            NSimpleLog.AddLog("N.HMI.Common.dll::Start() - Can not find \"" + str + "\"");
                        }
                    }
                }

                return WindowPtr;
            }
            catch (System.ComponentModel.Win32Exception ex)
            {
                if (exeFilename.IndexOf(".pdf") > 0 && ex.ErrorCode == -2147467259)
                {
                    MessageBox.Show("This computer doesn't have any application for \"PDF\"." + Environment.NewLine + "Please, install the Acrobat Reader.");
                }
                else
                {
                    MessageBox.Show(ex.Message);
                }
                return IntPtr.Zero;
            }
        }
        public static IntPtr Start(string exeFilename, string[] windowTitle, Boolean isBlocking, string argv,out Boolean isRunning)
        {
            try
            {
                IntPtr WindowPtr = IntPtr.Zero;
                if (exeFilename.IndexOf('\\') < 0)
                    exeFilename = AppDomain.CurrentDomain.BaseDirectory + exeFilename;

                if (windowTitle == null)
                {
                    isRunning = false;
                    if (!File.Exists(exeFilename))
                    {
                        
                        return IntPtr.Zero;
                    }
                    else
                    {
                        System.Diagnostics.Process process = null;
                        if (string.IsNullOrEmpty(argv))
                            process = System.Diagnostics.Process.Start(exeFilename);
                        else
                            process = System.Diagnostics.Process.Start(exeFilename, argv);

                        return process.Handle;
                    }
                }
                else
                {
                    WindowPtr = FindWindows(windowTitle);

                    //is Running Window
                    if (WindowPtr != IntPtr.Zero)
                    {
                        NWin32API.ActiveWindow(WindowPtr);
                        isRunning = true;
                    }
                    else
                    {
                        isRunning = false;
                        if (!File.Exists(exeFilename))
                        {
                            isRunning = false;
                            return IntPtr.Zero;
                        }

                        System.Diagnostics.Process process = null;
                        if (string.IsNullOrEmpty(argv))
                            process = System.Diagnostics.Process.Start(exeFilename);
                        else
                            process = System.Diagnostics.Process.Start(exeFilename, argv);

                        System.Threading.Thread.Sleep(250);

                        if (process != null && isBlocking)
                        {
                            //*
                            int cnt = 0;
                            do
                            {
                                System.Threading.Thread.Sleep(250);
                                WindowPtr = FindWindows(windowTitle);
                                Console.WriteLine("Windows:{0} Count{1}", WindowPtr.ToInt32(), cnt);
                                cnt++;
                            } while (WindowPtr == IntPtr.Zero && cnt < 30);
                            //*/ 

                        }

                    }

                    if (WindowPtr != IntPtr.Zero)
                    {
                        NWin32API.SendMessage(WindowPtr, NWin32API.WM_SYSCOMMAND, (IntPtr)NWin32API.SC_RESTORE, IntPtr.Zero);
                    }
                    else 
                    {
                        if (isBlocking)
                        {
                            string str = "";
                            foreach (string temp in windowTitle)
                            {
                                str += temp + ",";
                            }
                            str = str.Remove(str.Length - 1);
                            NSimpleLog.AddLog("N.HMI.Common.dll::Start() - Can not find \"" + str + "\"");
                        }
                    }
                }

                
                return WindowPtr;
            }
            catch (System.ComponentModel.Win32Exception ex)
            {
                if (exeFilename.IndexOf(".pdf") > 0 && ex.ErrorCode == -2147467259)
                {
                    MessageBox.Show("This computer doesn't have any application for \"PDF\"." + Environment.NewLine + "Please, install the Acrobat Reader.");
                }
                else
                {
                    MessageBox.Show(ex.Message);
                }

                isRunning = false;
                return IntPtr.Zero;
            }
        }
        public static void InitParameters(string exeFilename, string windowTitle, string argv, int UM_MSGID, object DataObj)
        {
            myData = new MesasgeData();
            myData.exeFilename = exeFilename;
            myData.windowTitle = windowTitle;
            myData.argv = argv;
            myData.UM_MSGID = UM_MSGID;
            myData.DataObj = DataObj;
        }
        public static void StartNSend(string exeFilename, string windowTitle,string argv, int UM_MSGID, object DataObj)
        {
            InitParameters(exeFilename, windowTitle, argv, UM_MSGID, DataObj);
            ProcessStartNSendDelegate ProcessStartNSendInvoker = new ProcessStartNSendDelegate(ProcessStartNSend); 
            ProcessStartNSendInvoker.BeginInvoke(false,null,null);

            //MethodInvoker myInvoker = new MethodInvoker(ProcessStartNSend);
            //myInvoker.BeginInvoke(null, null);
        }
        public static void StartNSend(string exeFilename, string windowTitle, string argv, int UM_MSGID, object DataObj, bool ForceToSend)
        {
            InitParameters(exeFilename, windowTitle, argv, UM_MSGID, DataObj);
            ProcessStartNSendDelegate ProcessStartNSendInvoker = new ProcessStartNSendDelegate(ProcessStartNSend);
            ProcessStartNSendInvoker.BeginInvoke(ForceToSend, null, null);

            //MethodInvoker myInvoker = new MethodInvoker(ProcessStartNSend);
            //myInvoker.BeginInvoke(null, null);
        }
        
    }
    #region INTER_PROGRAM_COMMUNICATION

    public struct MesasgeData
    {
        public string exeFilename;
        public string windowTitle;
        public string argv;
        public int UM_MSGID;
        public object DataObj;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ReqPoint
    {
        public int iHost;
        public int iTagId;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
        public byte[] szTagName;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 25)]
        public byte[] szUserName;
        public int iTreeID;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct PointList
    {
        public int iTagCnt;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
        public ReqPoint[] ReqList;
    } 
    public struct UNIVIEW_REQ_MSG
    {
        public int nHost;
    }

    #endregion
   
}
